home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / System / XADmaster / xad_dev / Sources / tools / xad2lha.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-04-01  |  28.5 KB  |  1,317 lines

  1. #define NAME         "xad2lha"
  2. #define DISTRIBUTION "(Freeware) "
  3. #define REVISION     "1"
  4. #define DATE         "15.04.2000"
  5.  
  6. /* Programmheader
  7.  
  8.     Name:        xad2lha
  9.     Author:        SDI
  10.     Distribution:    Freeware
  11.     Description:    recompresses file archives in lha format
  12.     Compileropts:    -
  13.     Linkeropts:    -gsi -l amiga
  14.  
  15.  1.0   19.08.99 : first version
  16.  1.1   15.04.00 : added support for disk archives
  17. */
  18.  
  19. #include <proto/xadmaster.h>
  20. #include <proto/exec.h>
  21. #include <proto/dos.h>
  22. #include <exec/memory.h>
  23. #include <dos/dosasl.h>
  24. #include <utility/hooks.h>
  25. #include "SDI_version.h"
  26. #include "SDI_compiler.h"
  27. #define SDI_TO_ANSI
  28. #include "SDI_ASM_STD_protos.h"
  29.  
  30. struct xadMasterBase *     xadMasterBase = 0;
  31. struct DosLibrary *     DOSBase = 0;
  32. struct ExecBase *     SysBase  = 0;
  33.  
  34. #define MINPRINTSIZE    51200    /* 50KB */
  35.  
  36. #define PARAM    "FROM/A,TO,PASSWORD/K,NOEXTERN/S,QUIET/S,HEADER0/S"
  37.  
  38. #define OPTIONS \
  39.   "FROM       The input archive file (no patterns allowed)\n"        \
  40.   "TO         The destination archive file\n"                \
  41.   "PASSWORD   A password for encrypted archives\n"            \
  42.   "NOEXTERN   Turns off usage of external clients\n"            \
  43.   "QUIET      Turns off progress report\n"                \
  44.   "HEADER0    Produces header level 0 files\n"
  45.  
  46. struct Args {
  47.   STRPTR   from;
  48.   STRPTR   to;
  49.   STRPTR   password;
  50.   ULONG    noextern;
  51.   ULONG    quiet;
  52.   ULONG    header0;
  53. };
  54.  
  55. void MakeEntry0(struct xadFileInfo *fi, STRPTR tmp, BPTR fh, STRPTR mem, ULONG size, ULONG *ressize);
  56. void MakeEntry2(struct xadFileInfo *fi, STRPTR tmp, BPTR fh, STRPTR mem, ULONG size, ULONG *ressize);
  57. ULONG MakeLH(STRPTR mem, ULONG size, ULONG bits);
  58. void ProcessEntry(struct xadFileInfo *fi, struct xadArchiveInfo *ai, struct Args *args, BPTR outfh,
  59.   STRPTR tmp, LONG disk);
  60.  
  61. ULONG start(void)
  62. {
  63.   ULONG ret = RETURN_FAIL;
  64.   struct DosLibrary *dosbase;
  65.  
  66.   SysBase = (*((struct ExecBase **) 4));
  67.   { /* test for WB and reply startup-message */
  68.     struct Process *task;
  69.     if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  70.     {
  71.       WaitPort(&task->pr_MsgPort);
  72.       Forbid();
  73.       ReplyMsg(GetMsg(&task->pr_MsgPort));
  74.       return RETURN_FAIL;
  75.     }
  76.   }
  77.  
  78.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  79.   {
  80.     LONG err = 0;
  81.     struct xadMasterBase *xadmasterbase;
  82.  
  83.     DOSBase = dosbase;
  84.     if((xadmasterbase = (struct xadMasterBase *)
  85.     OpenLibrary("xadmaster.library", 5)))
  86.     {
  87.       struct Args args;
  88.       struct RDArgs *rda;
  89.       
  90.       memset(&args, 0, sizeof(struct Args));
  91.       xadMasterBase = xadmasterbase;
  92.  
  93.       if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  94.       {
  95.         rda->RDA_ExtHelp = OPTIONS;
  96.  
  97.         if(ReadArgs(PARAM, (LONG *) &args, rda))
  98.         {
  99.           struct xadArchiveInfo *ai;
  100.     
  101.       if((ai = (struct xadArchiveInfo *) xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  102.           {
  103.         if(!(err = xadGetInfo(ai, XAD_INFILENAME, args.from, XAD_NOEXTERN, args.noextern,
  104.         args.password ? XAD_PASSWORD : TAG_IGNORE, args.password, TAG_DONE)))
  105.         {
  106.           STRPTR tmp;
  107.  
  108.           if((tmp = (STRPTR) AllocMem(2048, MEMF_ANY)))
  109.           {
  110.             BPTR outfh;
  111.             ULONG i;
  112.  
  113.             if((ai->xai_Flags & XADAIF_FILECORRUPT) && !args.quiet)
  114.               Printf("!!! The archive file has some corrupt data. !!!\n");
  115.  
  116.             if(!args.to)
  117.             {
  118.               i = strlen(args.from);
  119.               CopyMem(args.from, tmp, i+1);
  120.  
  121.           do
  122.           {
  123.             --i;
  124.             if(tmp[i] == '.')
  125.               tmp[i] = 0;
  126.           } while(i && tmp[i] != '/' && tmp[i] != ':'); 
  127.           CopyMem(".lha", tmp + strlen(tmp), 5);
  128.           args.to = tmp;
  129.             }
  130.  
  131.             if((outfh = Open(args.to, MODE_NEWFILE)))
  132.             {
  133.           struct xadFileInfo *fi;
  134.           struct xadDiskInfo *di;
  135.  
  136.           ret = 0;
  137.               fi = ai->xai_FileInfo;
  138.               di = ai->xai_DiskInfo;
  139.  
  140.           if(!args.quiet)
  141.             Printf("Original Crunched Ratio  OldCrun Name\n"
  142.             "------------------------------------------------------\n");
  143.  
  144.           while(fi && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  145.           {
  146.             ProcessEntry(fi, ai, &args, outfh, tmp, 0);
  147.               fi = fi->xfi_Next;
  148.               }
  149.           while(di && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  150.           {
  151.             struct xadArchiveInfo *aid;
  152.  
  153.                 if((aid = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
  154.                 {
  155.                   struct TagItem ti[5];
  156.  
  157.                 ti[0].ti_Tag = XAD_INFILENAME;
  158.                 ti[0].ti_Data = (ULONG) args.from;
  159.                 ti[1].ti_Tag = XAD_ENTRYNUMBER;
  160.                 ti[1].ti_Data = di->xdi_EntryNumber;
  161.                 ti[2].ti_Tag = XAD_NOEXTERN;
  162.                 ti[2].ti_Data = args.noextern;
  163.                 ti[3].ti_Tag = args.password ? XAD_PASSWORD : TAG_IGNORE;
  164.                 ti[3].ti_Data = (ULONG) args.password;
  165.                 ti[4].ti_Tag = TAG_DONE;
  166.  
  167.               if(!args.quiet)
  168.                     Printf("Processing disk entry %ld.\n", di->xdi_EntryNumber);
  169.                 if(!(i = xadGetDiskInfo(aid, XAD_INDISKARCHIVE, ti, TAG_DONE)))
  170.                 {
  171.                     if((aid->xai_Flags & XADAIF_FILECORRUPT) && !args.quiet)
  172.                       Printf("!!! Disk has some corrupt data. !!!\n");
  173.                     fi = aid->xai_FileInfo;
  174.                     while(fi && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  175.                     {
  176.                   ProcessEntry(fi, aid, &args, outfh, tmp, 1);
  177.                   fi = fi->xfi_Next;
  178.                 }
  179.                 xadFreeInfo(aid);
  180.               }
  181.               else if(!args.quiet)
  182.                  Printf("Failed to extract data form disk archive: %s\n", xadGetErrorText(i));
  183.               xadFreeObjectA(aid, 0);
  184.             }
  185.             di = di->xdi_Next;
  186.               }
  187.               NameFromFH(outfh, tmp, 2048);
  188.               Close(outfh);
  189.               SetProtection(tmp, FIBF_EXECUTE);
  190.             }
  191.             FreeMem(tmp, 2048);
  192.           }
  193.           xadFreeInfo(ai);
  194.         } /* xadGetInfo */
  195.  
  196.         xadFreeObjectA(ai, 0);
  197.           } /* xadAllocObject */
  198.  
  199.           FreeArgs(rda);
  200.         } /* ReadArgs */
  201.         FreeDosObject(DOS_RDARGS, rda);
  202.       } /* AllocDosObject */
  203.  
  204.       if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  205.         SetIoErr(ERROR_BREAK);
  206.  
  207.       if(!args.quiet)
  208.       {
  209.         if(err)
  210.       Printf("An error occured: %s\n", xadGetErrorText(err));
  211.         else if(ret)
  212.           PrintFault(IoErr(), 0);
  213.       }
  214.  
  215.       CloseLibrary((struct Library *) xadmasterbase);
  216.     } /* OpenLibrary xadmaster */
  217.     else
  218.       Printf("Could not open xadmaster.library\n");
  219.     CloseLibrary((struct Library *) dosbase);
  220.   } /* OpenLibrary dos */
  221.   return ret;
  222. }
  223.  
  224. void ProcessEntry(struct xadFileInfo *fi, struct xadArchiveInfo *ai, struct Args *args, BPTR outfh,
  225. STRPTR tmp, LONG disk)
  226. {
  227.   ULONG i, res = 0;
  228.  
  229.   if(fi->xfi_Flags & XADFIF_LINK)
  230.   {
  231.     if(!args->quiet)
  232.       Printf("Skipped Link\n");
  233.   }
  234.   else if(fi->xfi_Flags & XADFIF_DIRECTORY)
  235.   {
  236.     if(args->header0)
  237.       MakeEntry0(fi, tmp, outfh, 0, 0, &i);
  238.     else
  239.       MakeEntry2(fi, tmp, outfh, 0, 0, &i);
  240.     if(!args->quiet)
  241.       Printf("   <dir>    <dir>                %s\n", fi->xfi_FileName);
  242.   }
  243.   else if(fi->xfi_Flags & XADFIF_NOUNCRUNCHSIZE)
  244.   {
  245.     Printf("Skipping entry of unknown size: %s\n", fi->xfi_FileName);
  246.   }
  247.   else if(!fi->xfi_Size)
  248.   {
  249.     if(args->header0)
  250.       MakeEntry0(fi, tmp, outfh, 0, 0, &res);
  251.     else
  252.       MakeEntry2(fi, tmp, outfh, 0, 0, &res);
  253.     Printf("       0        0  0.0%%        0 %s\n", fi->xfi_FileName);
  254.   }
  255.   else
  256.   {
  257.     STRPTR outmem;
  258.  
  259.     if((outmem = (STRPTR) AllocMem(fi->xfi_Size, MEMF_ANY)))
  260.     {
  261.       if(disk)
  262.         i = xadDiskFileUnArc(ai, XAD_OUTMEMORY, outmem, XAD_ENTRYNUMBER,
  263.         fi->xfi_EntryNumber, XAD_OUTSIZE, fi->xfi_Size, TAG_DONE);
  264.       else
  265.         i = xadFileUnArc(ai, XAD_OUTMEMORY, outmem, XAD_ENTRYNUMBER,
  266.         fi->xfi_EntryNumber, XAD_OUTSIZE, fi->xfi_Size, TAG_DONE);
  267.       if(!i)
  268.       {
  269.         if(args->header0)
  270.           MakeEntry0(fi, tmp, outfh, outmem, fi->xfi_Size, &res);
  271.         else
  272.           MakeEntry2(fi, tmp, outfh, outmem, fi->xfi_Size, &res);
  273.         if(!args->quiet)
  274.     {
  275.       ULONG i = 0, j = 0;
  276.  
  277.       if(res < fi->xfi_Size)
  278.       {
  279.         i = ((fi->xfi_Size - res)*1000)/fi->xfi_Size;
  280.         j = i % 10;
  281.             i /= 10;
  282.           }
  283.           if(fi->xfi_Flags & XADFIF_GROUPED)
  284.             Printf("%8ld %8ld %2ld.%1ld%%   merged %s\n", fi->xfi_Size, res, i, j, fi->xfi_FileName);
  285.           else
  286.             Printf("%8ld %8ld %2ld.%1ld%% %8ld %s\n", fi->xfi_Size, res, i, j, fi->xfi_CrunchSize, fi->xfi_FileName);
  287.         }
  288.       }
  289.       else if(!args->quiet)
  290.         Printf("Failed to extract file %s: %s\n", fi->xfi_FileName, xadGetErrorText(i));
  291.     }
  292.     FreeMem(outmem, fi->xfi_Size);
  293.   }
  294. }
  295.  
  296. void Store32(STRPTR s, ULONG v)
  297. {
  298.   ULONG i;
  299.  
  300.   for( i = 0; i < 4; ++i)
  301.   {
  302.     *(s++) = v;
  303.     v >>= 8;
  304.   }
  305. }
  306.  
  307. void Store16(STRPTR s, ULONG v)
  308. {
  309.   *(s++) = v;
  310.   *s = v >> 8;
  311. }
  312.  
  313. /* Header structure!
  314.   UBYTE    HeaderSize              0  *
  315.   UBYTE    CheckSum             1  *
  316.   UBYTE*5  HeaderID             2  *
  317.   ULONG    CompSize             7  *
  318.   ULONG    Size                11  *
  319.   ULONG       Time                15  *
  320.   UBYTE    Attribute            19  *
  321.   UBYTE       Level (0)            20  *
  322.   UBYTE       NameSize            21  *
  323.   file name
  324.   UWORD       CRC                22+s
  325.   data
  326. */
  327.  
  328. void MakeEntry0(struct xadFileInfo *fi, STRPTR tmp, BPTR fh, STRPTR mem, ULONG size, ULONG *ressize)
  329. {
  330.   ULONG ns, cs, hs, j;
  331.  
  332.   tmp[2] = tmp[6] = '-';
  333.   tmp[3] = 'l';
  334.   tmp[4] = 'h';
  335.   tmp[5] = '0';
  336.   Store32(tmp+7, size);
  337.   Store32(tmp+11, size);
  338.   tmp[19] = fi->xfi_Protection;
  339.   tmp[20] = 0;
  340.  
  341.   xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date, XAD_GETDATEMSDOS, &ns, TAG_DONE);
  342.   Store32(tmp+15, ns);
  343.  
  344.   ns = strlen(fi->xfi_FileName) + (fi->xfi_Flags & XADFIF_DIRECTORY ? 1 : 0);
  345.   cs = strlen(fi->xfi_Comment);
  346.   hs = ns + cs + (cs ? 1 : 0);
  347.   tmp[21] = hs;
  348.  
  349.   hs += 22;
  350.   Store16(tmp+hs, size ? xadCalcCRC16(XADCRC16_ID1, 0, size, mem) : 0);
  351.  
  352.   for(j = 0; j < ns; ++j)
  353.     tmp[22 + j] = fi->xfi_FileName[j] == '/' ? '\\' : fi->xfi_FileName[j];
  354.   if(cs)
  355.   {
  356.     tmp[22+ns] = 0;
  357.     CopyMem(fi->xfi_Comment, tmp+22+ns+1, cs);
  358.   }
  359.   if(fi->xfi_Flags & XADFIF_DIRECTORY)
  360.     tmp[22+ns-1] = '/';
  361.   else
  362.   {
  363.     /* Compressable ? */
  364.     if(size && (ns = MakeLH(mem, size, 13)))
  365.     {
  366.       tmp[5] = '5';
  367.       size = ns;
  368.       Store32(tmp+7, size);
  369.     }
  370.   }
  371.  
  372.   *ressize = size;
  373.   for(cs = ns = 0; cs < hs; ++cs)
  374.     ns += tmp[2+cs];
  375.   tmp[1] = ns;
  376.   tmp[0] = hs;
  377.   Write(fh, tmp, hs+2);
  378.   if(size)
  379.     Write(fh, mem, size);
  380. }
  381.  
  382. #define TM_UREAD      00400 /* Read by owner */
  383. #define TM_UWRITE     00200 /* Write by owner */
  384. #define TM_UEXEC      00100 /* Execute/search by owner */
  385. #define TM_GREAD      00040 /* Read by group */
  386. #define TM_GWRITE     00020 /* Write by group */
  387. #define TM_GEXEC      00010 /* Execute/search by group */
  388. #define TM_OREAD      00004 /* Read by other */
  389. #define TM_OWRITE     00002 /* Write by other */
  390. #define TM_OEXEC     00001 /* Execute/search by other */
  391.  
  392. /* Header structure!
  393.   UWORD       TotalHeaderSize         0  *
  394.   UBYTE*5  HeaderID             2  *
  395.   ULONG    CompSize             7  *
  396.   ULONG    Size                11  *
  397.   ULONG       Time                15  *
  398.   UBYTE    Attribute            19  *
  399.   UBYTE       Level (2)            20  *
  400.   UWORD    CRC                    21  *
  401.   UBYTE    SystemID ('A')        23  *
  402.   UWORD    FirstExtHeaderSize        24
  403.   extended headers
  404.   data
  405. */
  406. void MakeEntry2(struct xadFileInfo *fi, STRPTR tmp, BPTR fh, STRPTR mem, ULONG size, ULONG *ressize)
  407. {
  408.   ULONG headersize = 26, i, j, k;
  409.  
  410.   tmp[2] = tmp[6] = '-';
  411.   tmp[3] = 'l';
  412.   tmp[4] = 'h';
  413.   Store32(tmp+7, size);
  414.   Store32(tmp+11, size);
  415.   tmp[19] = fi->xfi_Protection;
  416.   tmp[20] = 2;
  417.   Store16(tmp+21, size ? xadCalcCRC16(XADCRC16_ID1, 0, size, mem) : 0);
  418.   tmp[23] = 'A';
  419.  
  420.   xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date, XAD_GETDATEMSDOS, &k, TAG_DONE);
  421.   Store32(tmp+15, k);
  422.  
  423.   if(fi->xfi_Flags & XADFIF_DIRECTORY)
  424.   {
  425.     tmp[5] = 'd';
  426.     i = strlen(fi->xfi_FileName);
  427.     Store16(tmp + headersize-2, i+3); /* set header size */
  428.     tmp[headersize++] = 0x02;
  429.     for(j = 0; j < i; ++j)
  430.       tmp[headersize++] = fi->xfi_FileName[j] == '/' ? 0xFF : fi->xfi_FileName[j];
  431.     headersize += 2;
  432.   }
  433.   else
  434.   {
  435.     STRPTR m;
  436.  
  437.     tmp[5] = '0';
  438.     m = FilePart(fi->xfi_FileName);
  439.  
  440.     i = strlen(m);
  441.     Store16(tmp + headersize-2, i+3); /* set header size */
  442.     tmp[headersize] = 0x01;
  443.     CopyMem(m, tmp+headersize+1, i);
  444.     headersize += i+3;
  445.     if(m != fi->xfi_FileName)
  446.     {
  447.       i = m-fi->xfi_FileName-1;
  448.       Store16(tmp + headersize-2, i+3); /* set header size */
  449.       tmp[headersize++] = 0x02;
  450.       for(j = 0; j < i; ++j)
  451.         tmp[headersize++] = fi->xfi_FileName[j] == '/' ? 0xFF : fi->xfi_FileName[j];
  452.       headersize += 2;
  453.     }
  454.  
  455.     /* Compressable ? */
  456.     if(size && (i = MakeLH(mem, size, 13)))
  457.     {
  458.       tmp[5] = '5';
  459.       size = i;
  460.       Store32(tmp+7, size);
  461.     }
  462.   }
  463.  
  464.   *ressize = size;
  465.  
  466.   if(fi->xfi_Protection & 0xFFFFFF00)
  467.   {
  468.     /* store UNIX protection */
  469.     Store16(tmp + headersize-2, 5); /* set header size */
  470.     i = fi->xfi_Protection;
  471.     j = 0;
  472.  
  473.     if(!(i & FIBF_READ))    j |= TM_UREAD;
  474.     if(!(i & FIBF_WRITE))     j |= TM_UWRITE;
  475.     if(!(i & FIBF_EXECUTE))    j |= TM_UEXEC;
  476.     if(i & FIBF_GRP_READ)     j |= TM_GREAD;
  477.     if(i & FIBF_GRP_WRITE)    j |= TM_GWRITE;
  478.     if(i & FIBF_GRP_EXECUTE)    j |= TM_GEXEC;
  479.     if(i & FIBF_OTR_READ)     j |= TM_OREAD;
  480.     if(i & FIBF_OTR_WRITE)    j |= TM_OWRITE;
  481.     if(i & FIBF_OTR_EXECUTE)    j |= TM_OEXEC;
  482.  
  483.     tmp[headersize] = 0x50;
  484.     Store16(tmp+headersize+1, j);
  485.     headersize += 5;
  486.   }
  487.  
  488.   /* store ID's */
  489.   if(fi->xfi_OwnerUID || fi->xfi_OwnerGID)
  490.   {
  491.     Store16(tmp + headersize-2, 7); /* set header size */
  492.     tmp[headersize] = 0x51;
  493.     Store16(tmp + headersize+1, fi->xfi_OwnerGID);
  494.     Store16(tmp + headersize+3, fi->xfi_OwnerUID);
  495.     headersize += 7;
  496.   }
  497.  
  498.   /* store group name */
  499.   if(fi->xfi_GroupName)
  500.   {
  501.     i = strlen(fi->xfi_GroupName);
  502.     Store16(tmp + headersize-2, i+3); /* set header size */
  503.     tmp[headersize] = 0x52;
  504.     CopyMem(fi->xfi_GroupName, tmp+headersize+1, i);
  505.     headersize += i+3;
  506.   }
  507.  
  508.   /* store user name */
  509.   if(fi->xfi_UserName)
  510.   {
  511.     i = strlen(fi->xfi_UserName);
  512.     Store16(tmp + headersize-2, i+3); /* set header size */
  513.     tmp[headersize] = 0x53;
  514.     CopyMem(fi->xfi_UserName, tmp+headersize+1, i);
  515.     headersize += i+3;
  516.   }
  517.  
  518.   if(!(fi->xfi_Flags & XADFIF_NODATE))
  519.   {
  520.     /* store UNIX time stamp */
  521.     Store16(tmp + headersize-2, 7); /* set header size */
  522.     xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date, XAD_GETDATEUNIX, &k, TAG_DONE);
  523.     tmp[headersize] = 0x54;
  524.     Store32(tmp+headersize+1, k);
  525.     headersize += 7;
  526.   }
  527.  
  528.   /* store comment */
  529.   if(fi->xfi_Comment)
  530.   {
  531.     i = strlen(fi->xfi_Comment);
  532.     Store16(tmp + headersize-2, i+3); /* set header size */
  533.     tmp[headersize] = 0x71;
  534.     CopyMem(fi->xfi_Comment, tmp+headersize+1, i);
  535.     headersize += i+3;
  536.   }
  537.  
  538.   /* save the stuff */
  539.   Store16(tmp + headersize-2, 5);
  540.   tmp[headersize] = 0x00;
  541.   Store16(tmp + headersize+1, 0); /* clear CRC */
  542.   headersize += 5;
  543.   Store16(tmp + headersize-2, 0); /* clear last header size */
  544.   Store16(tmp, headersize);
  545.   Store16(tmp + headersize-4, xadCalcCRC16(XADCRC16_ID1, 0, headersize, tmp)); /* store CRC */
  546.   Write(fh, tmp, headersize);
  547.   if(size)
  548.     Write(fh, mem, size);
  549. }
  550.  
  551. /************************************************************************/
  552.  
  553. #define MAXMATCH            256    /* formerly F (not more than UCHAR_MAX + 1) */
  554. #define DICSIZ                (1 << 15)
  555. #define TXTSIZ                (DICSIZ * 2 + MAXMATCH)
  556. #define HSHSIZ                (1 << 15)
  557. #define THRESHOLD            3    /* choose optimal value */
  558. #define LIMIT                0x100
  559. #define UCHAR_MAX            ((1<<(sizeof(UBYTE)*8))-1)
  560. #define USHRT_MAX            ((1<<(sizeof(UWORD)*8))-1)
  561. #define NC                 (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
  562. #define    MAX_DICBIT            15
  563. #define NP                (MAX_DICBIT + 1)
  564. #define CHAR_BIT              8
  565. #define NT                (USHRT_BIT + 3)
  566. #define USHRT_BIT            16    /* (CHAR_BIT * sizeof(ushort)) */
  567. #define NPT                0x80
  568. #define CBIT                9    /* $\lfloor \log_2 NC \rfloor + 1$ */
  569. #define TBIT                 5    /* smallest integer such that (1 << TBIT) > * NT */
  570.  
  571.   STRPTR  lh5_inmem;
  572.   STRPTR  lh5_outmem;
  573.   ULONG   origsize;
  574.   ULONG   inpos;
  575.   ULONG   compsize;
  576.   ULONG   dicsiz;
  577.   ULONG   txtsiz;
  578.   UWORD   dicbit;
  579.   UWORD   maxmatch;
  580.   UWORD * hash;
  581.   UWORD * prev;
  582.   STRPTR  text;
  583.   STRPTR  too_flag;
  584.   STRPTR  buf;
  585.   UWORD   bufsiz;
  586.   LONG    unpackable;
  587.   ULONG   count;
  588.   ULONG   loc;
  589.   ULONG   encoded_origsize;
  590.   LONG    matchlen;
  591.   ULONG   pos;
  592.   ULONG   remainder;
  593.   ULONG   hval;
  594.   ULONG   matchpos;
  595.   UWORD   cpos;
  596.   UWORD   left[2 * NC - 1];
  597.   UWORD   right[2 * NC - 1];
  598.   UWORD   c_freq[2 * NC - 1];
  599.   UWORD   p_freq[2 * NP - 1];
  600.   UWORD   t_freq[2 * NT - 1];
  601.   UWORD   pt_code[NPT];
  602.   UWORD   c_code[NC];
  603.   UWORD   output_pos;
  604.   UWORD      output_mask;
  605.   UBYTE   pt_len[NPT];
  606.   UBYTE   c_len[NC];
  607.   LONG      pbit;
  608.   LONG      np;
  609.   UBYTE   depth;
  610.   UWORD   len_cnt[17];
  611.   WORD      n;
  612.   UWORD * sort;
  613.   WORD    heapsize;
  614.   WORD    heap[NC + 1];
  615.   UWORD * freq;
  616.   STRPTR  len;
  617.   UBYTE   subbitbuf;
  618.   UBYTE   bitcount;
  619.  
  620. /************************************************************************/
  621.  
  622. static ULONG getbytes(APTR mem, ULONG size)
  623. {
  624.   if(inpos+size > origsize)
  625.     size = origsize-inpos;
  626.   if(size)
  627.   {
  628.     CopyMem(lh5_inmem + inpos, mem, size);
  629.     inpos += size;
  630.   }
  631.   return size;
  632. }
  633.  
  634. static void putcode(UBYTE n, UWORD x)        /* Write rightmost n bits of x */
  635. {
  636.   while(n >= bitcount)
  637.   {
  638.     n -= bitcount;
  639.     subbitbuf += x >> (USHRT_BIT - bitcount);
  640.     x <<= bitcount;
  641.     if(compsize < origsize)
  642.       lh5_outmem[compsize++] = subbitbuf;
  643.     else
  644.       unpackable = 1;
  645.     subbitbuf = 0;
  646.     bitcount = CHAR_BIT;
  647.   }
  648.   subbitbuf += x >> (USHRT_BIT - bitcount);
  649.   bitcount -= n;
  650. }
  651.  
  652. static void putbits(UBYTE n, UWORD x)        /* Write rightmost n bits of x */
  653. {
  654.   x <<= USHRT_BIT - n;
  655.   while(n >= bitcount)
  656.   {
  657.     n -= bitcount;
  658.     subbitbuf += x >> (USHRT_BIT - bitcount);
  659.     x <<= bitcount;
  660.     if(compsize < origsize)
  661.       lh5_outmem[compsize++] = subbitbuf;
  662.     else
  663.       unpackable = 1;
  664.     subbitbuf = 0;
  665.     bitcount = CHAR_BIT;
  666.   }
  667.   subbitbuf += x >> (USHRT_BIT - bitcount);
  668.   bitcount -= n;
  669. }
  670.  
  671. static void init_putbits(void)
  672. {
  673.   bitcount = CHAR_BIT;
  674.   subbitbuf = 0;
  675. }
  676.  
  677. static void make_code(LONG n, UBYTE len[], UWORD code[])
  678. {
  679.   UWORD weight[17];    /* 0x10000ul >> bitlen */
  680.   UWORD start[17];    /* start code */
  681.   UWORD j, k;
  682.   LONG i;
  683.  
  684.   j = 0;
  685.   k = 1 << (16 - 1);
  686.   for(i = 1; i <= 16; i++)
  687.   {
  688.     start[i] = j;
  689.     j += (weight[i] = k) * len_cnt[i];
  690.     k >>= 1;
  691.   }
  692.   for(i = 0; i < n; i++)
  693.   {
  694.     j = len[i];
  695.     code[i] = start[j];
  696.     start[j] += weight[j];
  697.   }
  698. }
  699.  
  700. static void count_len(LONG i)        /* call with i = root */
  701. {
  702.   if(i < n)
  703.     len_cnt[depth < 16 ? depth : 16]++;
  704.   else
  705.   {
  706.     depth++;
  707.     count_len(left[i]);
  708.     count_len(right[i]);
  709.     depth--;
  710.   }
  711. }
  712.  
  713. static void make_len(LONG root)
  714. {
  715.   LONG i, k;
  716.   ULONG cum;
  717.  
  718.   for(i = 0; i <= 16; i++)
  719.     len_cnt[i] = 0;
  720.   count_len(root);
  721.   cum = 0;
  722.   for(i = 16; i > 0; i--)
  723.   {
  724.     cum += len_cnt[i] << (16 - i);
  725.   }
  726.   cum &= 0xffff;
  727.   /* adjust len */
  728.   if(cum)
  729.   {
  730.     len_cnt[16] -= cum;    /* always len_cnt[16] > cum */
  731.     do
  732.     {
  733.       for(i = 15; i > 0; i--)
  734.       {
  735.     if(len_cnt[i])
  736.     {
  737.       len_cnt[i]--;
  738.       len_cnt[i + 1] += 2;
  739.       break;
  740.     }
  741.       }
  742.     } while(--cum);
  743.   }
  744.   /* make len */
  745.   for(i = 16; i > 0; i--)
  746.   {
  747.     k = len_cnt[i];
  748.     while(k > 0)
  749.     {
  750.       len[*sort++] = i;
  751.       k--;
  752.     }
  753.   }
  754. }
  755.  
  756. static void downheap(LONG i) /* priority queue; send i-th entry down heap */
  757. {
  758.   WORD j, k;
  759.  
  760.   k = heap[i];
  761.   while((j = 2 * i) <= heapsize)
  762.   {
  763.     if(j < heapsize && freq[heap[j]] > freq[heap[j + 1]])
  764.       j++;
  765.     if(freq[k] <= freq[heap[j]])
  766.       break;
  767.     heap[i] = heap[j];
  768.       i = j;
  769.   }
  770.   heap[i] = k;
  771. }
  772.  
  773. static WORD make_tree(LONG nparm, UWORD freqparm[], UBYTE lenparm[], UWORD codeparm[]) /* make tree, calculate len[], return root */
  774. {
  775.   WORD i, j, k, avail;
  776.  
  777.   n = nparm;
  778.   freq = freqparm;
  779.   len = lenparm;
  780.   avail = n;
  781.   heapsize = 0;
  782.   heap[1] = 0;
  783.   for(i = 0; i < n; i++)
  784.   {
  785.     len[i] = 0;
  786.     if(freq[i])
  787.       heap[++heapsize] = i;
  788.   }
  789.   if(heapsize < 2)
  790.   {
  791.     codeparm[heap[1]] = 0;
  792.     return heap[1];
  793.   }
  794.   for(i = heapsize / 2; i >= 1; i--)
  795.     downheap(i);    /* make priority queue */
  796.   sort = codeparm;
  797.   do
  798.   {            /* while queue has at least two entries */
  799.     i = heap[1];    /* take out least-freq entry */
  800.     if(i < n)
  801.       *sort++ = i;
  802.     heap[1] = heap[heapsize--];
  803.     downheap(1);
  804.     j = heap[1];    /* next least-freq entry */
  805.     if(j < n)
  806.       *sort++ = j;
  807.     k = avail++;    /* generate new node */
  808.     freq[k] = freq[i] + freq[j];
  809.     heap[1] = k;
  810.     downheap(1);    /* put into queue */
  811.     left[k] = i;
  812.     right[k] = j;
  813.   } while (heapsize > 1);
  814.   sort = codeparm;
  815.   make_len(k);
  816.   make_code(nparm, lenparm, codeparm);
  817.   return k;        /* return root */
  818. }
  819.  
  820. static void encode_c(WORD c)
  821. {
  822.   putcode(c_len[c], c_code[c]);
  823. }
  824.  
  825. static void encode_p(UWORD p)
  826. {
  827.   UWORD c, q;
  828.  
  829.   c = 0;
  830.   q = p;
  831.   while(q)
  832.   {
  833.     q >>= 1;
  834.     c++;
  835.   }
  836.   putcode(pt_len[c], pt_code[c]);
  837.   if(c > 1)
  838.     putbits(c - 1, p);
  839. }
  840.  
  841. static void count_t_freq(void)
  842. {
  843.   WORD i, k, n, count;
  844.  
  845.   for(i = 0; i < NT; i++)
  846.     t_freq[i] = 0;
  847.   n = NC;
  848.   while(n > 0 && c_len[n - 1] == 0)
  849.     n--;
  850.   i = 0;
  851.   while(i < n)
  852.   {
  853.     k = c_len[i++];
  854.     if(k == 0)
  855.     {
  856.       count = 1;
  857.       while(i < n && c_len[i] == 0)
  858.       {
  859.         i++;
  860.         count++;
  861.       }
  862.       if(count <= 2)
  863.         t_freq[0] += count;
  864.       else if(count <= 18)
  865.         t_freq[1]++;
  866.       else if(count == 19)
  867.       {
  868.         t_freq[0]++;
  869.         t_freq[1]++;
  870.       }
  871.       else
  872.         t_freq[2]++;
  873.     }
  874.     else
  875.       t_freq[k + 2]++;
  876.   }
  877. }
  878.  
  879. static void write_pt_len(WORD n, WORD nbit, WORD i_special)
  880. {
  881.   WORD i, k;
  882.  
  883.   while(n > 0 && pt_len[n - 1] == 0)
  884.     n--;
  885.   putbits(nbit, n);
  886.   i = 0;
  887.   while(i < n)
  888.   {
  889.     k = pt_len[i++];
  890.     if(k <= 6)
  891.       putbits(3, k);
  892.     else
  893.       putbits(k - 3, (UWORD) (USHRT_MAX << 1));
  894.     if(i == i_special)
  895.     {
  896.       while(i < 6 && pt_len[i] == 0)
  897.     i++;
  898.       putbits(2, i - 3);
  899.     }
  900.   }
  901. }
  902.  
  903. static void write_c_len(void)
  904. {
  905.   WORD i, k, n, count;
  906.  
  907.   n = NC;
  908.   while(n > 0 && c_len[n - 1] == 0)
  909.     n--;
  910.   putbits(CBIT, n);
  911.   i = 0;
  912.   while(i < n)
  913.   {
  914.     k = c_len[i++];
  915.     if(k == 0)
  916.     {
  917.       count = 1;
  918.       while(i < n && c_len[i] == 0)
  919.       {
  920.         i++;
  921.     count++;
  922.       }
  923.       if(count <= 2)
  924.       {
  925.     for(k = 0; k < count; k++)
  926.       putcode(pt_len[0], pt_code[0]);
  927.       }
  928.       else if(count <= 18)
  929.       {
  930.     putcode(pt_len[1], pt_code[1]);
  931.     putbits(4, count - 3);
  932.       }
  933.       else if(count == 19)
  934.       {
  935.     putcode(pt_len[0], pt_code[0]);
  936.     putcode(pt_len[1], pt_code[1]);
  937.     putbits(4, 15);
  938.       }
  939.       else
  940.       {
  941.     putcode(pt_len[2], pt_code[2]);
  942.     putbits(CBIT, count - 20);
  943.       }
  944.     }
  945.     else
  946.       putcode(pt_len[k + 2], pt_code[k + 2]);
  947.   }
  948. }
  949.  
  950. static void send_block(void)
  951. {
  952.   UBYTE flags = 0;
  953.   UWORD i, k, root, pos, size;
  954.  
  955.   root = make_tree(NC, c_freq, c_len, c_code);
  956.   size = c_freq[root];
  957.   putbits(16, size);
  958.   if(root >= NC)
  959.   {
  960.     count_t_freq();
  961.     root = make_tree(NT, t_freq, pt_len, pt_code);
  962.     if(root >= NT)
  963.     {
  964.       write_pt_len(NT, TBIT, 3);
  965.     }
  966.     else
  967.     {
  968.       putbits(TBIT, 0);
  969.       putbits(TBIT, root);
  970.     }
  971.     write_c_len();
  972.   }
  973.   else
  974.   {
  975.     putbits(TBIT, 0);
  976.     putbits(TBIT, 0);
  977.     putbits(CBIT, 0);
  978.     putbits(CBIT, root);
  979.   }
  980.   root = make_tree(np, p_freq, pt_len, pt_code);
  981.   if(root >= np)
  982.   {
  983.     write_pt_len(np, pbit, -1);
  984.   }
  985.   else
  986.   {
  987.     putbits(pbit, 0);
  988.     putbits(pbit, root);
  989.   }
  990.   pos = 0;
  991.   for(i = 0; i < size; i++)
  992.   {
  993.     if(i % CHAR_BIT == 0)
  994.       flags = buf[pos++];
  995.     else
  996.       flags <<= 1;
  997.     if(flags & (1 << (CHAR_BIT - 1)))
  998.     {
  999.       encode_c(buf[pos++] + (1 << CHAR_BIT));
  1000.       k = buf[pos++] << CHAR_BIT;
  1001.       k += buf[pos++];
  1002.       encode_p(k);
  1003.     }
  1004.     else
  1005.       encode_c(buf[pos++]);
  1006.     if(unpackable)
  1007.       return;
  1008.   }
  1009.   for(i = 0; i < NC; i++)
  1010.     c_freq[i] = 0;
  1011.   for(i = 0; i < np; i++)
  1012.     p_freq[i] = 0;
  1013. }
  1014.  
  1015. void output_st1(UWORD c, UWORD p)
  1016. {
  1017.   output_mask >>= 1;
  1018.   if(output_mask == 0)
  1019.   {
  1020.     output_mask = 1 << (CHAR_BIT - 1);
  1021.     if(output_pos >= bufsiz - 3 * CHAR_BIT)
  1022.     {
  1023.       send_block();
  1024.       if(unpackable)
  1025.         return;
  1026.       output_pos = 0;
  1027.     }
  1028.     cpos = output_pos++;
  1029.     buf[cpos] = 0;
  1030.   }
  1031.   buf[output_pos++] = (unsigned char) c;
  1032.   c_freq[c]++;
  1033.   if(c >= (1 << CHAR_BIT))
  1034.   {
  1035.     buf[cpos] |= output_mask;
  1036.     buf[output_pos++] = (unsigned char) (p >> CHAR_BIT);
  1037.     buf[output_pos++] = (unsigned char) p;
  1038.     c = 0;
  1039.     while(p)
  1040.     {
  1041.       p >>= 1;
  1042.       c++;
  1043.     }
  1044.     p_freq[c]++;
  1045.   }
  1046. }
  1047.  
  1048. static void init_slide(void)
  1049. {
  1050.   ULONG i;
  1051.  
  1052.   for(i = 0; i < HSHSIZ; i++)
  1053.   {
  1054.     hash[i] = 0;
  1055.     too_flag[i] = 0;
  1056.   }
  1057. }
  1058.  
  1059. static void insert(void)
  1060. {
  1061.   prev[pos & (dicsiz - 1)] = hash[hval];
  1062.   hash[hval] = pos;
  1063. }
  1064.  
  1065. static void update(void)
  1066. {
  1067.   ULONG i, j;
  1068.   LONG n, m;
  1069.  
  1070.   i = 0;
  1071.   j = dicsiz;
  1072.   m = txtsiz-dicsiz;
  1073.   while(m-- > 0)
  1074.     text[i++] = text[j++];
  1075.  
  1076.   n = getbytes(&text[txtsiz - dicsiz], (ULONG) dicsiz);
  1077.  
  1078.   remainder += n;
  1079.   encoded_origsize += n;
  1080.  
  1081.   pos -= dicsiz;
  1082.   for(i = 0; i < HSHSIZ; i++)
  1083.   {
  1084.     j = hash[i];
  1085.     hash[i] = (j > dicsiz) ? j - dicsiz : 0;
  1086.     too_flag[i] = 0;
  1087.   }
  1088.   for(i = 0; i < dicsiz; i++)
  1089.   {
  1090.     j = prev[i];
  1091.     prev[i] = (j > dicsiz) ? j - dicsiz : 0;
  1092.   }
  1093. }
  1094.  
  1095. static void get_next(void)
  1096. {
  1097.   remainder--;
  1098.   if(++pos >= txtsiz - maxmatch)
  1099.   {
  1100.     update();
  1101.   }
  1102.   hval = ((hval << 5) ^ text[pos + 2]) & (ULONG)(HSHSIZ - 1);
  1103. }
  1104.  
  1105. static void match_insert(void)
  1106. {
  1107.   ULONG scan_pos, scan_end, len;
  1108.   STRPTR a, b;
  1109.   ULONG chain, off, h, max;
  1110.  
  1111.   max = maxmatch; /* MAXMATCH; */
  1112.   if(matchlen < THRESHOLD - 1)
  1113.     matchlen = THRESHOLD - 1;
  1114.   matchpos = pos;
  1115.  
  1116.   off = 0;
  1117.   for(h = hval; too_flag[h] && off < maxmatch - THRESHOLD;)
  1118.   {
  1119.     h = ((h << 5) ^ text[pos + (++off) + 2]) & (ULONG)(HSHSIZ - 1);
  1120.   }
  1121.   if(off == maxmatch - THRESHOLD)
  1122.     off = 0;
  1123.   for(;;)
  1124.   {
  1125.     chain = 0;
  1126.     scan_pos = hash[h];
  1127.     scan_end = (pos > dicsiz) ? pos + off - dicsiz : off;
  1128.     while(scan_pos > scan_end)
  1129.     {
  1130.       chain++;
  1131.       if(text[scan_pos + matchlen - off] == text[pos + matchlen])
  1132.       {
  1133.         a = text + scan_pos - off;
  1134.         b = text + pos;
  1135.         for(len = 0; len < max && *a++ == *b++; len++)
  1136.           ;
  1137.         if(len > matchlen)
  1138.         {
  1139.       matchpos = scan_pos - off;
  1140.       if((matchlen = len) == max)
  1141.       {
  1142.         break;
  1143.           }
  1144.     }
  1145.       }
  1146.       scan_pos = prev[scan_pos & (dicsiz - 1)];
  1147.     }
  1148.     if(chain >= LIMIT)
  1149.       too_flag[h] = 1;
  1150.  
  1151.     if(matchlen > off + 2 || off == 0)
  1152.       break;
  1153.     max = off + 2;
  1154.     off = 0;
  1155.     h = hval;
  1156.   }
  1157.   prev[pos & (dicsiz - 1)] = hash[hval];
  1158.   hash[hval] = pos;
  1159. }
  1160.  
  1161. static void encode_start_st1(void)
  1162. {
  1163.   LONG i;
  1164.  
  1165.   if(dicbit <= (MAX_DICBIT - 2))
  1166.   {
  1167.      pbit = 4;    /* lh4,5 etc. */
  1168.      np = 14;
  1169.   }
  1170.   else
  1171.   {
  1172.     pbit = 5;    /* lh6 */
  1173.     np = 16;
  1174.   }
  1175.  
  1176.   for(i = 0; i < NC; i++)
  1177.     c_freq[i] = 0;
  1178.   for(i = 0; i < np; i++)
  1179.     p_freq[i] = 0;
  1180.   output_pos = output_mask = 0;
  1181.   init_putbits();
  1182.   buf[0] = 0;
  1183. }
  1184.  
  1185. static void encode_end_st1(void)
  1186. {
  1187.   if(!unpackable)
  1188.   {
  1189.     send_block();
  1190.     putbits(CHAR_BIT - 1, 0);    /* flush remaining bits */
  1191.   }
  1192. }
  1193.  
  1194. static void encode(void)
  1195. {
  1196.   LONG lastmatchlen, i;
  1197.   ULONG lastmatchoffset;
  1198.  
  1199.   compsize = count = 0;
  1200.   unpackable = 0;
  1201.  
  1202.   init_slide();  
  1203.  
  1204.   encode_start_st1();
  1205.  
  1206.   for(i = 0; i < dicsiz; ++i)
  1207.     text[dicsiz+i] = ' ';
  1208.  
  1209.   remainder = getbytes(&text[dicsiz], txtsiz-dicsiz);
  1210.   encoded_origsize = remainder;
  1211.   matchlen = THRESHOLD - 1;
  1212.   pos = dicsiz;
  1213.  
  1214.   if(matchlen > remainder)
  1215.     matchlen = remainder;
  1216.   hval = ((((text[dicsiz] << 5) ^ text[dicsiz + 1]) << 5) ^ text[dicsiz + 2]) & (ULONG)(HSHSIZ - 1);
  1217.  
  1218.   insert();
  1219.   while(remainder > 0 && !unpackable)
  1220.   {
  1221.     lastmatchlen = matchlen;  lastmatchoffset = pos - matchpos - 1;
  1222.     --matchlen;
  1223.     get_next();
  1224.     match_insert();
  1225.     if(matchlen > remainder)
  1226.       matchlen = remainder;
  1227.     if(matchlen > lastmatchlen || lastmatchlen < THRESHOLD)
  1228.     {
  1229.       output_st1(text[pos - 1], 0);
  1230.       count++;
  1231.     }
  1232.     else
  1233.     {
  1234.       output_st1(lastmatchlen + (UCHAR_MAX + 1 - THRESHOLD), (lastmatchoffset) & (dicsiz-1) );
  1235.       --lastmatchlen;
  1236.  
  1237.       while(--lastmatchlen > 0)
  1238.       {
  1239.         get_next();
  1240.         insert();
  1241.         count++;
  1242.       }
  1243.       get_next();
  1244.       matchlen = THRESHOLD - 1;
  1245.       match_insert();
  1246.       if(matchlen > remainder)
  1247.         matchlen = remainder;
  1248.     }
  1249.   }
  1250.   encode_end_st1();
  1251. }
  1252.  
  1253. static STRPTR alloc_buf(void)
  1254. {
  1255.   bufsiz = 16 * 1024 * 2;    /* 65408U; */
  1256.   while(!(buf = (STRPTR) AllocMem(bufsiz, MEMF_ANY)))
  1257.   {
  1258.     bufsiz = (bufsiz / 10) * 9;
  1259.     if(bufsiz < 4 * 1024)
  1260.       break;
  1261.   }
  1262.   return buf;
  1263. }
  1264.  
  1265. ULONG MakeLH(STRPTR mem, ULONG size, ULONG bits)
  1266. {
  1267.   ULONG ok = 0;
  1268.   STRPTR mem2;
  1269.   
  1270.   if((mem2 = (STRPTR) AllocVec(size, MEMF_CLEAR)))
  1271.   {
  1272.     lh5_inmem = mem;
  1273.     lh5_outmem = mem2;
  1274.     origsize = size;
  1275.     compsize = 0;
  1276.     depth = 0;
  1277.     inpos = 0;
  1278.  
  1279.     maxmatch = MAXMATCH;
  1280.     dicbit = bits;
  1281.     dicsiz = (1 << dicbit);
  1282.     txtsiz = dicsiz*2+maxmatch;
  1283.  
  1284.     if(alloc_buf())
  1285.     {
  1286.       if((hash = (UWORD *) AllocVec(HSHSIZ * 2, MEMF_CLEAR)))
  1287.       {
  1288.     if((prev = (UWORD *) AllocVec(DICSIZ * 2, MEMF_CLEAR)))
  1289.     {
  1290.       if((text = (STRPTR) AllocVec(TXTSIZ, MEMF_CLEAR)))
  1291.       {
  1292.         if((too_flag = (STRPTR) AllocVec(HSHSIZ, MEMF_CLEAR)))
  1293.         {
  1294.           encode();
  1295.           if(compsize < size && !unpackable)
  1296.           {
  1297.             CopyMem(mem2, mem, compsize);
  1298.             size = compsize;
  1299.             ok = 1;
  1300.           }
  1301.           FreeVec(too_flag);
  1302.         }
  1303.         FreeVec(text);
  1304.       }
  1305.       FreeVec(prev);
  1306.     }
  1307.     FreeVec(hash);
  1308.       }
  1309.       FreeMem(buf, bufsiz);
  1310.     }
  1311.     FreeVec(mem2);
  1312.   }
  1313.  
  1314.   return ok ? size : 0;
  1315. }
  1316.  
  1317.